package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.lang.tree.TreeUtil;
import com.zzyl.constant.CacheConstant;
import com.zzyl.constant.SuperConstant;
import com.zzyl.dto.ResourceDto;
import com.zzyl.entity.Resource;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.ResourceMapper;
import com.zzyl.service.ResourceService;
import com.zzyl.utils.NoProcessing;
import com.zzyl.vo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

@Service

public class ResourceServiceImpI implements ResourceService {
    @Autowired
    private ResourceMapper resourceMapper;
    @Cacheable(value = CacheConstant.RESOURCE_LIST,key = "#resourceDto.hashCode()")
    @Override
    public List<ResourceVo> selectList(ResourceDto resourceDto) {
        List<Resource> resourceList  = resourceMapper.selectList(resourceDto) ;
        return BeanUtil.copyToList(resourceList,ResourceVo.class);
    }
    @Cacheable(value = CacheConstant.RESOURCE_TREE,key = "#resourceDto.hashCode()")
    @Override
    public TreeVo resourceTreeVo(ResourceDto resourceDto) {
        //1.构建查询条件
        resourceDto.setParentResourceNo(NoProcessing.processString(SuperConstant.ROOT_DEPT_PARENT_ID));//100001
        resourceDto.setResourceType(SuperConstant.MENU);//只查询菜单
        resourceDto.setDataState(SuperConstant.DATA_STATE_0);
        //2.执行查询所有菜单集合
        List<Resource> resourceList = resourceMapper.selectList(resourceDto);
        if (CollectionUtil.isEmpty(resourceList)) {
            throw new RuntimeException("资源不存在");
        }
        //3.使用hutool构建属性工具进行获取树形数据
        //创建属性配置对象
        TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
        //修改默认树节点
        treeNodeConfig.setNameKey("label");
        List<Tree<String>> treeList = TreeUtil.build(resourceList, SuperConstant.ROOT_DEPT_PARENT_ID, treeNodeConfig, (resource, treeNode) -> {
            treeNode.setName(resource.getResourceName());//封装节点名字
            treeNode.setId(resource.getResourceNo());//封装节点编号
            treeNode.setParentId(resource.getParentResourceNo());//封装树节点父节点编号
        });
        //4、封装结果返回
        List<TreeItemVo> children = BeanUtil.copyToList(treeList, TreeItemVo.class);
        // TreeUtil.build() 构建树形方法
        // 参数1：resourceList 设置所有数据给到hutool
        // 参数2：SuperConstant.ROOT_PARENT_ID  告诉hutool根节点编号
        // 参数3：treeNodeConfig，给生成树形节点对象属性起别名
        // 参数4：(resource, treeNode) -> {} 遍历每个资源对象构建树节点treeNode对象
        //实例封装智慧养老院对象TreeItemVo
        TreeItemVo zhylyItemVo = TreeItemVo.builder()
                .id(SuperConstant.ROOT_PARENT_ID)
                .label("智慧养老")
                .children(children)
                .build();
        //实例TreeVo对象中的items属性集合List<TreeItVo>,添加智慧养老院对象TreeItemVo
        List<TreeItemVo> items = new ArrayList();
        items.add(zhylyItemVo);
        //实例封装TreeVo,封装TreeVo对象中的items属性，zhylyItemVo
        return TreeVo.builder()
                .items(items)
                .build();
    }
          @Caching(evict = {
                  @CacheEvict(value = CacheConstant.RESOURCE_LIST,allEntries = true),
                  @CacheEvict(value = CacheConstant.RESOURCE_TREE,allEntries = true)
          })
    @Override
    public Boolean createResource(ResourceDto resourceDto) {

        //1.ResourceDto转换为Resource
        Resource resource = BeanUtil.toBean(resourceDto, Resource.class);
        //2.获取父节点对象的状态同步给当前Resource对象
        //获取父节点对象
        Resource parentResource= resourceMapper.selectByRespurceNo(resource.getParentResourceNo());
        //将父节点对象状态封装给当前Resource对象
          resource.setDataState(parentResource.getDataState());

        //3.生成当前Resource对象资源编号，封装给Resource对象
        String resourceNo=createResourceNo(resource);

        //4.Resource对象插入到数据库中
        resource.setResourceNo(resourceNo);
        resourceMapper.insertSelective(resource);
        return true;
    }
    //定义动态菜单
    @Override
    public List<MenuVo> menus(Long mgtUserId) {
        //1、查询用户对应的所有的菜单数据
        List<MenuVo> menuVoList = resourceMapper.findListByUserId(mgtUserId);
        //2、定义返回的树形菜单
        TreeNodeConfig treeNodeConfig=new TreeNodeConfig();
        treeNodeConfig.setIdKey("resourceNo");
        treeNodeConfig.setParentIdKey("parentResourceNo");
        //3、利用hutool工具实现菜单构建菜单
        List<Tree<String>> treeList = TreeUtil.build(menuVoList, SuperConstant.ROOT_DEPT_PARENT_ID, treeNodeConfig, (treeNode, menvo) -> {
            menvo.setName(treeNode.getName());
            menvo.setId(treeNode.getResourceNo());
            menvo.setParentId(treeNode.getParentResourceNo());
            menvo.putExtra("path", treeNode.getPath());
            menvo.putExtra("redirect", "/" + treeNode.getName());
            menvo.putExtra("mata", new MenuMetaVo(treeNode.getName(), "", null));
        });
        //转换类型封装返回
        List<MenuVo>menuVos=BeanUtil.copyToList(treeList,MenuVo.class);
        return menuVos;
    }


    private String createResourceNo(Resource resource) {
        //1、如果当前新增节点是菜单并且父节点有效数字层级大于4，抛出异常
        if (resource.getResourceType().equals(SuperConstant.MENU) && NoProcessing.processString(resource.getParentResourceNo()).length()/3>4) {
            throw new BaseException(BasicEnum.RESOURCE_DEPTH_UPPER_LIMIT);
        }
        //2、根据父节点编号查询子节点列表
        ResourceDto resourceDto = ResourceDto.builder()
                .parentResourceNo(resource.getParentResourceNo()).build();
        List<Resource> resourceList = resourceMapper.selectList(resourceDto);
        //3、判断子节点列表有没有数据
        String resourceNo="";
        if (CollectionUtil.isEmpty(resourceList)){
            //3.1、没有数据计算第一个子节点编号，调用工具类NoProcessing.createNo(父节点编号，flase)生成编号
            resourceNo=NoProcessing.createNo(resource.getResourceNo(),false);
        }else {
            //3.2有数据
            //获取最大的子节点编号
            Long maxNo = resourceList.stream()
                    .map(resource1 -> Long.valueOf(resource1.getResourceNo()))
                    .max(Comparator.comparing(Long::longValue))
                    .get();

            //调用工具类NoProcessing.createNo(最大子节点编号，true)生成编号
            resourceNo = NoProcessing.createNo(maxNo.toString(), true);
        }

        //4、返回编号
        return resourceNo;
    }
}
